package com.unitd.frame.springweb.upload.multipart.stream;

import javax.servlet.ServletInputStream;
import java.io.FilterInputStream;
import java.io.IOException;

/**
 * @desc 自定义的文件输入流类,实现过滤输入流类,用于处理在上传文件中,需要进行的过滤操作
 * @filename PartInputStream.java
 * @copyright www.unitd.com
 * @author Hudan
 * @version 1.0
 * @date 2017/4/10
 */
public class PartInputStream extends FilterInputStream {
	private String boundary;
	private byte[] buf = new byte[65536];
	private int count;
	private int pos;
	private boolean eof;

	public PartInputStream(ServletInputStream in, String boundary) throws IOException {
		super(in);
		this.boundary = boundary;
	}

	/**
	 * @desc 读取文件流对象
	 * @throws IOException
	 */
	private void fill() throws IOException {
		if (!this.eof) {
			if (this.count > 0) {
				if (this.count - this.pos != 2) {
					throw new IllegalStateException("fill() detected illegal buffer state");
				}

				System.arraycopy(this.buf, this.pos, this.buf, 0, this.count - this.pos);
				this.count -= this.pos;
				this.pos = 0;
			}

			int boundaryLength = this.boundary.length();

			int part;
			for (int maxRead = this.buf.length - boundaryLength - 2; this.count < maxRead; this.count += part) {
				part = ((ServletInputStream) this.in).readLine(this.buf, this.count, this.buf.length - this.count);
				if (part == -1) {
					throw new IOException("unexpected end of part");
				}

				if (part >= boundaryLength) {
					this.eof = true;

					for (int i = 0; i < boundaryLength; ++i) {
						if (this.boundary.charAt(i) != this.buf[this.count + i]) {
							this.eof = false;
							break;
						}
					}

					if (this.eof) {
						break;
					}
				}
			}
		}
	}

	/**
	 * @desc 读取文件流
	 * @return 读取到的文件大小
	 * @throws IOException
	 */
	@Override
	public int read() throws IOException {
		if (this.count - this.pos <= 2) {
			this.fill();
			if (this.count - this.pos <= 2) {
				return -1;
			}
		}
		return this.buf[this.pos++] & 255;
	}

	/**
	 * @desc 读取文件刘对象
	 * @param bytes 文件字节对象
	 * @return
	 * @throws IOException
	 */
	@Override
	public int read(byte[] bytes) throws IOException {
		return this.read(bytes, 0, bytes.length);
	}

	/**
	 * @desc 从指定位置读取指定长度的文件字节对象
	 * @param bytes 文件字节对象
	 * @param off 起始位置
	 * @param len 读取长度
	 * @return
	 * @throws IOException
	 */
	@Override
	public int read(byte[] bytes, int off, int len) throws IOException {
		byte total = 0;
		if (len == 0) {
			return 0;
		} else {
			int avail = this.count - this.pos - 2;
			if (avail <= 0) {
				this.fill();
				avail = this.count - this.pos - 2;
				if (avail <= 0) {
					return -1;
				}
			}

			int copy = Math.min(len, avail);
			System.arraycopy(this.buf, this.pos, bytes, off, copy);
			this.pos += copy;

			int total1;
			for (total1 = total + copy; total1 < len; total1 += copy) {
				this.fill();
				avail = this.count - this.pos - 2;
				if (avail <= 0) {
					return total1;
				}

				copy = Math.min(len - total1, avail);
				System.arraycopy(this.buf, this.pos, bytes, off + total1, copy);
				this.pos += copy;
			}
			return total1;
		}
	}

	/**
	 * @desc 判断文件输入流还能否可读
	 * @return
	 * @throws IOException
	 */
	@Override
	public int available() throws IOException {
		int avail = this.count - this.pos - 2 + this.in.available();
		return avail < 0 ? 0 : avail;
	}

	/**
	 * @desc 关闭文件流读取对象
	 * @throws IOException
	 */
	@Override
	public void close() throws IOException {
		if (!this.eof) {
			while (true) {
				if (this.read(this.buf, 0, this.buf.length) != -1) {
					continue;
				}
			}
		}
	}
}